package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.MyException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {

        //先获取用户信息Vo (基本信息)  UserInfo较为复杂
        UserInfoVo userInfoVo = userInfoFeignClient.getUserInfoVo(userId).getData();
        Assert.notNull(userInfoVo, "查询用户信息不能为空");
        Long itemId = tradeVo.getItemId();

        //定义变量，为了封装数据使用
        //订单原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //减免总金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //订单总价
        BigDecimal orderAmount = new BigDecimal("0.00");
        //订单明细集合
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //订单减免明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        String itemType = tradeVo.getItemType();
        //判断订单项目的付费类型  1001专辑  1002声音  1003会员
        if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)) {
            Long albumId = itemId;
            AlbumInfo albumInfo = albumInfoFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfo, "查询专辑不存在");

            //在用户已付款专辑表中，查看用户是否购买专辑
            Boolean isPaidAlbum = userInfoFeignClient.userIsPaidAlbum(albumId, userId).getData();
            if (isPaidAlbum) {
                throw new MyException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }

            //计算专辑三个价格 原价，优惠，折后
            //判断用户是不是vip
            Integer isVip = userInfoVo.getIsVip();
            //0不是vip 1是vip 还要考虑过期没
            //如果是vip，并且到期时间晚于当前时间
            if (isVip.intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //原始价格
                originalAmount = albumInfo.getPrice();
                //优惠价格 derateAmount  -1表示没有折扣
                if (albumInfo.getVipDiscount().intValue() != -1) {
                    //100打8折，优惠20
                    // 原价*（10-折扣） / 10
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
            } else {
                //不是vip
                originalAmount = albumInfo.getPrice();
                //优惠价格 derateAmount  -1表示没有折扣
                if (albumInfo.getDiscount().intValue() != -1) {
                    //100打8折，优惠20
                    // 原价*（10-折扣） / 10
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
            }
            //无论如何将折后价格赋值
            orderAmount = originalAmount.subtract(derateAmount);

            //  订单明细集合 List<OrderDetailVo> orderDetailVoList
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(albumInfo.getPrice());
            orderDetailVoList.add(orderDetailVo);

            //订单减免明细列表  List<OrderDerateVo>  orderDerateVoList
            // 原始价格 - 最终价格 != 0 有优惠
            if (originalAmount.subtract(orderAmount).doubleValue() != 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                orderDerateVoList.add(orderDerateVo);
            }
        }
        else if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)) {
            //查几个音频，小于等于0直接给你抛咯
            Integer trackCount = tradeVo.getTrackCount();
            if (trackCount.intValue() <= 0) {
                throw new MyException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            Long trackId = itemId;
            //获取下单的声音列表
            //传入所选的id和选的选项（后10个后20个当前）
            //通过这俩值获取购买的声音信息集合（已去掉买过的了）
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(trackId, trackCount);
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            //获取albumId
            Long albumId = trackInfoList.get(0).getAlbumId();
            AlbumInfo albumInfo = albumInfoFeignClient.getAlbumInfo(albumId).getData();
            originalAmount = tradeVo.getTrackCount().intValue() > 0 ? albumInfo.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount())) : albumInfo.getPrice();
            //计算订单总价
            orderAmount = originalAmount;

            //循环遍历声音集合对象赋值订单明细
            orderDetailVoList = trackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                return orderDetailVo;
            }).collect(Collectors.toList());

        }
        else if (itemType.equals(SystemConstant.ORDER_ITEM_TYPE_VIP)) {
            Long Id = itemId;
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(Id);
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "vip数据为空");

            //计算三个价格：原始价格  、 优惠价格  、最终价格
            originalAmount = vipServiceConfig.getPrice();
            orderAmount = vipServiceConfig.getDiscountPrice();
            derateAmount = originalAmount.subtract(orderAmount);

            //订单明细集合 List<OrderDetailVo> orderDetailVoList
            //订单减免明细列表  List<OrderDerateVo>  orderDerateVoList
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName("VIP会员" + vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(vipServiceConfig.getDiscountPrice());
            orderDetailVoList.add(orderDetailVo);

            //订单减免
            if (originalAmount.subtract(orderAmount).doubleValue() != 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(originalAmount.subtract(orderAmount));
                orderDerateVoList.add(orderDerateVo);
            }
        }

        //把数据封装到OrderInfoVo中
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //购买类型 ：vip 专辑  声音
        orderInfoVo.setItemType(tradeVo.getItemType());
        //原始价格
        orderInfoVo.setOriginalAmount(originalAmount);
        //优惠价格
        orderInfoVo.setDerateAmount(derateAmount);
        //最终价格
        orderInfoVo.setOrderAmount(orderAmount);
        //订单明细
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        //优惠明细
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        //设置默认支付方式
        orderInfoVo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);

        //7 防止重复提交
        //防止重复提交，添加数据到redis里面
        String tradeNoKey = "user:trade:" + userId;
        // 定义一个流水号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo);
        //向后传递tradeNo
        orderInfoVo.setTradeNo(tradeNo);

        //8 数据安全校验
        //  生成签名
        Map<String, Object> parameterMap = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        String sign = SignHelper.getSign(parameterMap);
        orderInfoVo.setSign(sign);

        //9 返回OrderInfoVo对象数据
        return orderInfoVo;
    }

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    //返回一个订单编号
    //锁定金额检查金额扣减金额对象  AccountDeductVo
    @Override
//    @GlobalTransactional(rollbackFor = Exception.class)
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //JSON.parseObject将JSON字符串转化为相应对象
        //这里将orderInfoVo转化为JSON再转为Map
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay", SystemConstant.ORDER_PAY_WAY_WEIXIN);
        //查看是否过期  orderInfoVo中有个时间戳
        //通过当前时间-时间戳  > 500000判断
        SignHelper.checkSign(map);

        //防止重复提交,通过交易号
        String tradeNo = orderInfoVo.getTradeNo();
        Assert.notNull(tradeNo, "订单号是空的");
        //整个key他俩一块搁redis里  key就是userId
        String tradeNoKey = "user:trade" + userId;
        String script = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        Boolean flag = (Boolean) redisTemplate.execute(new DefaultRedisScript(script, Boolean.class), Arrays.asList(tradeNoKey), tradeNo);

        //开始下单
        //让交易号充当订单号
        String orderNo = tradeNo;
        //添加失败抛异常，不能重复提交
        if (!flag) {
            throw new MyException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
        }

        //如果支付方式是通过余额
        //TODO 微信方式没做处理？？
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
            //扣减用户余额
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            if (result.getCode() != 200) {
                throw new MyException(result.getCode(), result.getMessage());
            }
        }

        OrderInfo orderInfo = saveOrder(orderInfoVo, userId, orderNo);

        //????????
        //  创建用户购买记录对象
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        //  记录用户购买信息
        userPaidRecordVo.setOrderNo(orderNo);
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());
        //  购买项目的Id 专辑Id，声音Id, 服务配置Id: 在哪? order_detail.item_id
        List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
        userPaidRecordVo.setItemIdList(itemIdList);
        //  远程调用：
        Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
        //  判断
        if (200 != userResult.getCode()) {
            throw new MyException(211, "新增购买记录异常");
        }
        //  返回订单编号
        return orderNo;
    }

    @Override
    public void orderCancel(long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo.getOrderStatus().equals("0901")) {//未支付进行取消操作
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
            orderInfoMapper.updateById(orderInfo);
        }
    }

    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private RedissonClient redissonClient;

    private OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {

        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setOrderNo(orderNo);
        String orderTitle = orderInfoVo.getOrderDetailVoList().get(0).getItemName();
        orderInfo.setOrderTitle(orderTitle);
        orderInfo.setUserId(userId);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfoMapper.insert(orderInfo);
        //订单明细 首先判断有没有明细
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDetailVoList())) {
            //OrderDetailVo中没有orderId
            orderInfoVo.getOrderDetailVoList().forEach(orderDetailVo -> {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            });
        }

        //订单见面 首先判断有没有减免
        if (!CollectionUtils.isEmpty(orderInfoVo.getOrderDerateVoList())) {
            orderInfoVo.getOrderDerateVoList().forEach(orderDerateVo -> {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            });
        }

        //判断支付方式
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay())) {
            //余额支付
            //查看订单明细
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, orderInfo.getId()));
            //赋值订单明细
            orderInfo.setOrderDetailList(orderDetailList);
            //判断当前订单状态。
            if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID)) {
                orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
                orderInfoMapper.updateById(orderInfo);
            }
        } else if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(orderInfo.getPayWay())) {
            //微信支付
            //延迟消息
            //创建普通队列
            RBlockingQueue<Object> blockingQueue = redissonClient.getBlockingQueue(MqConst.EXCHANGE_CANCEL_ORDER);
            //转为延迟队列
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
            //向延迟队列发送消息，设置延迟时间
            delayedQueue.offer(orderInfo.getId().toString(), 30, TimeUnit.MINUTES);
        }
        return orderInfo;
    }

}